package bank;

import java.util.ArrayList;
import java.util.List;

/**
A bank account has a balance that can be changed by 
deposits and withdrawals.
*/
public class BankAccount
{  
	// Constants
	public static final String ACCOUNT_CLOSED = "Closed";
	public static final String ACCOUNT_SUSPENDED = "Suspended";
	public static final String ACCOUNT_OPEN = "Open";
	
	// Attributes
	private String accountStatus = ACCOUNT_CLOSED;
	private List<Double> transactions;
	private int accountNumber = 0;
	private double balance = 0;
	
	
   /**
   Constructs a bank account with a zero balance
   @param anAccountNumber The account number for this account
   */
   public BankAccount(int anAccountNumber)
   {   
	  transactions = new ArrayList<Double>();
	  this.accountNumber = anAccountNumber;
      this.setStatus(ACCOUNT_OPEN);
      this.balance = 0;
   }

   /**
   Constructs a bank account with a given balance
   @param anAccountNumber The account number for this account
   @param initialBalance The initial balance
   */
   public BankAccount(int anAccountNumber, double initialBalance)
   {   
	  transactions = new ArrayList<Double>();
	  this.accountNumber = anAccountNumber;
      this.setStatus(ACCOUNT_OPEN);
      this.deposit(initialBalance);
      System.out.println();
   }

   /**
   Gets the account number of this bank account.
   @return The account number
   */
   public int getAccountNumber()
   {   
      return this.accountNumber;
   }

   /**
   Deposits money into the bank account.
   @param amount The amount to deposit
   */
   public void deposit(double amount)
   {  
      
	  if (this.isOpen() && amount > 0)
	  {
		  double newBalance = balance + amount;
		  this.balance = newBalance;
	      this.addTransaction(amount);
	  }
   }

   /**
   Withdraws money from the bank account.
   @param amount The amount to withdraw
   */
   public void withdraw(double amount)
   {   
	   if (this.isOpen() && amount > 0 && amount <= this.balance)
		  {
			  double newBalance = balance - amount;
			  this.balance = newBalance;
		      this.addTransaction(-1 * amount); // amount * -1 makes number negative
		  }
   }

   /**
   Gets the current balance of the bank account.
   @return The current balance
   */
   public double getBalance()
   {   
      return this.balance;
   }
   
   // Account state setters
   /**
   Suspends the account it is called on
   */
   public void suspend()
   {
	   if (!this.isClosed())
	   {
		   this.setStatus(ACCOUNT_SUSPENDED);
	   }
   }
   
   /**
   Closes the account it is called on
   as long as the balance is 0.00
   Otherwise, it suspends it
   */
   public void close()
   {
		if (this.getBalance() == 0)
		{
			this.setStatus(ACCOUNT_CLOSED);
		}
		else
		{
			this.setStatus(ACCOUNT_SUSPENDED);
		}
   }
   
   /**
   Opens the account it is called on
   */
   public void open()
   {
	   if (!this.isClosed())
	   {
		   this.setStatus(ACCOUNT_OPEN);
	   }
   }
   
   /**
   Sets status of account
   @param status The status you wish to set
   */
   private void setStatus(String status)
   {
	   this.accountStatus = status;
   }
   
   // Account state checkers
   /**
   Checks to see if account is open
   @return True if open, false if suspended or closed
   */
   public boolean isOpen()
   {
	   return this.accountStatus.equals(ACCOUNT_OPEN);
   }
   
   /**
   Checks to see if account is suspended
   @return True if suspended, false if open or closed
   */
   public boolean isSuspended()
   {
	   return this.accountStatus.equals(ACCOUNT_SUSPENDED);
   }
   
   /**
   Checks to see if account is closed
   @return True if closed, false if open or suspended
   */
   public boolean isClosed()
   {
	   return this.accountStatus.equals(ACCOUNT_CLOSED);
   }
   
   /**
   Adds transaction to transaction list
   @param amount The amount of the transaction
   */
   public void addTransaction(double amount)
   {
	   this.transactions.add(amount);
   }
   
   /**
   Returns list of transactions as a String
   @return String of transactions
   */
   public String transactionsString()
   {
	   String outputString = "Account #" + this.accountNumber + " transactions:\n\n";
	   int transactionNumber = 0;
	   for (Double amount : this.transactions)
	   {
		   transactionNumber++;
		   outputString = outputString + transactionNumber + ": " + amount + "\n";
	   }
	   outputString = outputString + "balance = " + this.getBalance() + "\n";
	   outputString = outputString + "End of transactions\n\n";
	   return outputString;
   }
   
   /**
   Returns a number of how many transactions the account has performed
   @return The number of transactions
   */
   public int numTransactions()
   {
	   return this.transactions.size();
   }
   
   /**
   Gets status of the account
   @return The status of the account, either open, suspended, or closed
   */
   public String getStatus()
   {
	   if (this.isOpen())
	   {
		   return ACCOUNT_OPEN;
	   }
	   else if (this.isSuspended())
	   {
		   return ACCOUNT_SUSPENDED;
	   }
	   else if (this.isClosed())
	   {
		   return ACCOUNT_CLOSED;
	   }
	   else
	   {
		   return "No Status!";
	   }
   }
   
   /**
   Determines if two accounts have equal balances
   @return boolean
   */
   public boolean equals(Object o)
   {
	   if (o instanceof BankAccount)
	   {
		   return (Math.abs((this.balance - (((BankAccount) o).getBalance()))) < .01);
	   }
	   else
	   {
		   return false;
	   }
   }
}